/*
 * {comment of class}
 *
 * @author (C) <a href="http://www.carfield.com.hk">Carfield Yim</a>, 2005
 */
package hk.com.carfield.task;

import hk.com.carfield.core.Context;
import hk.com.carfield.item.Directory;
import hk.com.carfield.util.FileUtil;
import hk.com.carfield.util.LogUtil;
import hk.com.carfield.util.UrlUtil;
import hk.com.carfield.web.Request;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.TreeMap;

/**
 * @author carfield
 * 
 */
public final class ResourceService implements Executor {
	int updated, added;

	private void deleteEmptyMetaFolder(final File file) {
		// remove empty metafoler
		final File metaFolder = FileUtil.metaFolder(file);
		final File oldThumbnail = new File(metaFolder, "thumbnail.jpg");
		if (oldThumbnail.exists()) {
			oldThumbnail.delete();
		}
		if (metaFolder.listFiles() != null) {
			for (final File child : metaFolder.listFiles()) {
				if (child.isDirectory()) {
					for (final File grandChild : child.listFiles()) {
						grandChild.delete();
					}
					child.delete();
				}
			}
		}
		if (metaFolder.list() == null || metaFolder.list().length == 0) {
			metaFolder.delete();
		}
	}

	private void deleteOutDatedMeta(final File file, final File cache) {
		final File[] metas = file.listFiles(new FilenameFilter() {
			public boolean accept(final File dir, final String name) {
				if (name.startsWith(FileUtil.metaFolderTag() + ".")) {
					return true;
				} else {
					return false;
				}
			}
		});
		if (metas != null) {
			for (int i = 0; i < metas.length; i++) {
				final String fileName = metas[i].getName().substring(
						FileUtil.metaFolderTag().length() + 1);
				if (!new File(metas[i].getParentFile(), fileName).exists()) {
					LogUtil.log("outdated meta: " + metas[i].getAbsolutePath());
					metas[i].renameTo(new File(cache, metas[i].getName()));
				}
			}
		}
	}

	private int process(final Context c, final File file, int count,
			final TreeMap<Long, String> sortedMap) throws IOException {
		deleteEmptyMetaFolder(file);
		if (file.isDirectory()) {
			// TODO do we need to select file not existed but still at DB to
			// handle?
			deleteOutDatedMeta(file, c.config.getCacheDir());
			final File[] childs = file.listFiles(c.config.displayFilter());
			if (childs != null) {
				for (int i = 0; i < childs.length; i++) {
					count += process(c, childs[i], 0, sortedMap);
				}
			}
		} else {
			final String path = UrlUtil.getRelativePath(c.config, file);
			Long lastModified = file.lastModified();
			while (sortedMap.containsKey(lastModified)) {
				// prevent being drop by same lastModified
				lastModified++;
			}
			sortedMap.put(lastModified, path);
			// TODO check if file in big5/unicode??
		}
		return ++count;
	}

	public int runPerDay(final Context c) throws IOException {
		final Thread thread = new Thread(new Runnable() {
			public void run() {
				try {
					final long init = System.currentTimeMillis();
					updated = 0;
					added = 0;
					final TreeMap<Long, String> sortedMap = new TreeMap<Long, String>(
							java.util.Collections.reverseOrder());
					process(c, c.config.getRoot(), 0, sortedMap);
					Directory.init(sortedMap);
					c.mailMan.send("DB updated", "updated: " + updated
							+ "\t added: " + added + "\ntime taken for init: "
							+ (System.currentTimeMillis() - init)
							/ (60d * 1000) + "min");
				} catch (final Exception t) {
					LogUtil.error(t, c.mailMan);
				}
			}
		});
		thread.start();
		return 0;
	}

	public int runPerRequest(final Context c, final Request r, final File l) {
		return 0;
	}

	public int runPerWeek(final Context c) {
		return 0;
	}
}